package com.itheima.pinda.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.pinda.base.id.IdGenerate;
import com.itheima.pinda.biz.FileBiz;
import com.itheima.pinda.dao.AttachmentMapper;
import com.itheima.pinda.database.mybatis.conditions.Wraps;
import com.itheima.pinda.database.mybatis.conditions.query.LbqWrapper;
import com.itheima.pinda.dozer.DozerUtils;
import com.itheima.pinda.exception.BizException;
import com.itheima.pinda.file.domain.FileDO;
import com.itheima.pinda.file.domain.FileDeleteDO;
import com.itheima.pinda.file.dto.AttachmentDTO;
import com.itheima.pinda.file.dto.AttachmentResultDTO;
import com.itheima.pinda.file.dto.FilePageReqDTO;
import com.itheima.pinda.file.entity.Attachment;
import com.itheima.pinda.file.entity.File;
import com.itheima.pinda.properties.FileServerProperties;
import com.itheima.pinda.service.AttachmentService;
import com.itheima.pinda.strategy.FileStrategy;
import com.itheima.pinda.utils.DateUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.annotation.Resources;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.plaf.ListUI;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class AttachmentServiceImpl extends ServiceImpl<AttachmentMapper, Attachment> implements AttachmentService {
    @Resource
    private IdGenerate<Long> idGenerate;
    @Autowired
    private FileBiz fileBiz;
    @Autowired
    private DozerUtils dozer;
    @Resource
    private FileStrategy fileStrategy;
    @Autowired
    private FileServerProperties fileProperties;

    @Override
    public AttachmentDTO upload(MultipartFile multipartFile, Long id, String bizType, String bizId, Boolean isSingle) {
        if (StringUtils.isNotEmpty(bizType) && StringUtils.isEmpty(bizId)) {
            bizId = String.valueOf(idGenerate.generate());
        }
        File file = fileStrategy.upload(multipartFile);
        Attachment attachment = dozer.map(file, Attachment.class);
        attachment.setBizId(bizId);
        attachment.setBizType(bizType);
        setDate(attachment);
        if (isSingle) {
            remove(Wraps.<Attachment>lbQ().eq(Attachment::getBizId, bizId).eq(Attachment::getBizType, bizType));
        }
        if (id != null && id > 0) {
            attachment.setId(id);
            updateById(attachment);
        } else {
            attachment.setId(idGenerate.generate());
            save(attachment);
        }
        return dozer.map(attachment, AttachmentDTO.class);
    }

    @Override
    public void remove(Long[] ids) {
        if (ArrayUtils.isEmpty(ids)) {
            return;
        }

        //查询数据库
        List<Attachment> list = list(Wraps.<Attachment>lbQ().in(Attachment::getId, ids));
        if (list.isEmpty()) {
            return;
        }

        //删除数据库中的记录
        super.removeByIds(Arrays.asList(ids));

        //对象格式处理
        List<FileDeleteDO> fileDeleteDOList = list.stream().map((file) ->
                FileDeleteDO.builder()
                        .relativePath(file.getRelativePath()) //文件在服务器的相对路径
                        .fileName(file.getFilename()) //唯一文件名
                        .group(file.getGroup()) //fastDFS返回的组 用于FastDFS
                        .path(file.getPath()) //fastdfs 的路径
                        .build()
        ).collect(Collectors.toList());

        //删除文件
        fileStrategy.delete(fileDeleteDOList);
    }

    @Override
    public void removeByBizIdAndBizType(String bizId, String bizType) {
        //根据业务类和业务id查询数据库
        List<Attachment> list = super.list(
                Wraps.<Attachment>lbQ()
                        .eq(Attachment::getBizId, bizId)
                        .eq(Attachment::getBizType, bizType));
        if (list.isEmpty()) {
            return;
        }
        remove(list.stream().mapToLong(Attachment::getId).boxed().toArray(Long[]::new));
    }


    @Override
    public void download(HttpServletRequest request, HttpServletResponse response, Long[] ids) throws Exception {
        //根据文件Id查询数据库
        List<Attachment> list = list(Wraps.<Attachment>lbQ().in(Attachment::getId, ids));
        down(request, response, list);
    }

    @Override
    public void downloadByBiz(HttpServletRequest request, HttpServletResponse response, String[] bizTypes, String[] bizIds) throws Exception {
        List<Attachment> list = super.list(
                Wraps.<Attachment>lbQ()
                        .in(Attachment::getBizType, bizTypes)
                        .in(Attachment::getBizId, bizIds));

        down(request, response, list);
    }

    /**
     * 查询附件分页数据
     *
     * @param page
     * @param data
     * @return
     */
    public IPage<Attachment> page(Page<Attachment> page, FilePageReqDTO data) {
        Attachment attachment = dozer.map(data, Attachment.class);
        // ${ew.customSqlSegment} 语法一定要手动eq like 等 不能用lbQ!
        LbqWrapper<Attachment> wrapper = Wraps.<Attachment>lbQ()
                .like(Attachment::getSubmittedFileName, attachment.getSubmittedFileName())
                .like(Attachment::getBizType, attachment.getBizType())
                .like(Attachment::getBizId, attachment.getBizId())
                .eq(Attachment::getDataType, attachment.getDataType())
                .orderByDesc(Attachment::getId);
        return baseMapper.page(page, wrapper);
    }

    @Override
    public List<AttachmentResultDTO> find(String[] bizTypes, String[] bizIds) {
        return baseMapper.find(bizTypes, bizIds);
    }

    /**
     * 文件下载
     *
     * @param request
     * @param response
     * @param list
     */
    private void down(HttpServletRequest request, HttpServletResponse response, List<Attachment> list) throws Exception {
        if (list.isEmpty()) {
            throw BizException.wrap("您下载的文件不存在");
        }

        List<FileDO> fileDOList = list.stream().map(file -> FileDO.builder()
                .url(file.getUrl())
                .submittedFileName(file.getSubmittedFileName())
                .size(file.getSize())
                .dataType(file.getDataType())
                .build()).collect(Collectors.toList());
        fileBiz.down(fileDOList, request, response);
    }

    private void setDate(Attachment attachment) {
        LocalDateTime now = LocalDateTime.now();
        attachment.setCreateMonth(DateUtils.formatAsYearMonthEn(now));
        attachment.setCreateWeek(DateUtils.formatAsYearWeekEn(now));
        attachment.setCreateDay(DateUtils.formatAsDateEn(now));
    }
}
